package com.aizuda.easyManagerTool.service.terminal.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aizuda.easy.security.server.EasySecurityServer;
import com.aizuda.easyManagerTool.config.YmlVarConfig;
import com.aizuda.easyManagerTool.domian.dto.terminal.SSHInfoDTO;
import com.aizuda.easyManagerTool.domian.dto.terminal.SSHMessageDTO;
import com.aizuda.easyManagerTool.domian.entity.server.ServerLogEntity;
import com.aizuda.easyManagerTool.domian.vo.server.ServerCompleteVO;
import com.aizuda.easyManagerTool.domian.vo.setting.SettingUserVO;
import com.aizuda.easyManagerTool.domian.vo.socket.SocketMessageVO;
import com.aizuda.easyManagerTool.mapper.server.ServerMapper;
import com.aizuda.easyManagerTool.service.server.ServerLogService;
import com.aizuda.easyManagerTool.service.socket.SocketEventService;
import com.aizuda.easyManagerTool.service.socket.impl.SocketSessionManager;
import com.aizuda.easyManagerTool.service.terminal.ScriptService;
import com.aizuda.easyManagerTool.util.SSHManagerUtil;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.annotation.Resource;
import java.io.*;
import java.util.function.BiConsumer;

/**
 * 处理ssh消息
 */
@Service("ssh")
@Slf4j
public class SSHServiceImpl extends AbstractSSHTemplate implements SocketEventService, ScriptService {

    @Resource
    ServerLogService serverLogService;
    @Resource
    ServerMapper serverMapper;
    @Resource
    EasySecurityServer easySecurityServer;
    @Resource
    YmlVarConfig ymlVarConfig;

    @Override
    public void init(String token,WebSocketSession message,TerminalSessionManager.Manager manager,SSHMessageDTO messageDTO)throws Exception {
        SettingUserVO authUser = (SettingUserVO) easySecurityServer.getAuthUser(token.split(":")[0]);
        manager.createLog(authUser.getId(),authUser.getTenantId(),messageDTO.getServerId(),ymlVarConfig.getPath());
        ServerCompleteVO serverCompleteVO = serverMapper.findById(messageDTO.getServerId());
        BeanUtil.copyProperties(serverCompleteVO,messageDTO.getInfo());
        manager.setSshMessageDTO(messageDTO);
        SSHManagerUtil.templateChannelShell(manager,(channelShell) ->{
            Thread thread = new Thread(() -> {
                try {
                    manager.setThread(Thread.currentThread());
                    sendMessage(manager, channelShell, message, "command");
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            thread.setName("ssh-"+messageDTO.getInfo().getServerName());
            thread.start();
        });

    }

    @Override
    public void onClose(String token, WebSocketSession session, CloseStatus closeStatus) throws IOException {
        TerminalSessionManager.Manager manager = TerminalSessionManager.setGet(token);
        closeEvent(manager);
    }

    @Override
    public void connect(TerminalSessionManager.Manager manager,SSHMessageDTO messageDTO) throws Exception {
        SSHManagerUtil.templateChannelShell(manager,(channelShell) -> {
            OutputStream outputStream = null;
            try {
                String command = messageDTO.getCommand();
                if (StrUtil.isNotEmpty(command)) {
                    setCommand(channelShell,command);
                }
            }catch(Exception e){
                close(manager);
                if(outputStream != null){
                    try {
                        outputStream.close();
                    } catch (IOException ex) {}
                }
            }
        });
    }

    @Override
    void close(TerminalSessionManager.Manager manager) {
        ServerLogEntity serverLogEntity = new ServerLogEntity();
        serverLogEntity.setServerId(manager.getManagerLog().getServerId());
        String path = manager.getManagerLog().getPath();
        if(StrUtil.isEmpty(path)){
            return;
        }
        path = path.substring(path.lastIndexOf("/") + 1);
        serverLogEntity.setLogPath(ymlVarConfig.getFullPath()+path);
        serverLogEntity.setUserId(manager.getManagerLog().getUserId());
        serverLogEntity.setStartTime(manager.getManagerLog().getStartTime());
        serverLogEntity.setEndTime(manager.getManagerLog().getEndTime());
        serverLogEntity.setTenantId(manager.getManagerLog().getTenantId());
        serverLogService.insert(serverLogEntity);
    }

    SocketMessageVO<String> socketMessageVO = new SocketMessageVO<String>();
    @Override
    public String execScript(String topic, SettingUserVO user, SSHInfoDTO sshInfoDTO, String shPath, String parameter, BiConsumer<String, WebSocketSession> callBack) {
        //得到socket
        StringBuilder result = new StringBuilder();
        SocketMessageVO<String> socketMessage = BeanUtil.copyProperties(socketMessageVO, SocketMessageVO.class);
        WebSocketSession webSocketSession = SocketSessionManager.get(user);
        socketMessage.setType(topic);
        try {
            TerminalSessionManager.Manager manager = new TerminalSessionManager.Manager();
            log.debug("执行脚本 {}",sshInfoDTO.getServerIp());
            Session session = SSHManagerUtil.setSession(manager, sshInfoDTO);
            ChannelSftp channelSftp = SSHManagerUtil.setChannelSFTP(session, manager);
            String path = "/tmp/";
            channelSftp.cd(path);
            // 上传文件 sh/xx/xxx.sh
            ClassPathResource resource = new ClassPathResource(shPath);
            channelSftp.put(resource.getStream(), resource.getName());
            channelSftp.chmod(0755,resource.getName());
            // 执行脚本
            path += resource.getName();
            String script = "sh " + path + " "+parameter;
            ChannelExec  channelExec = SSHManagerUtil.setChannelExec(session, manager,"sed -i \"s/\\r//\" "+path);
            channelExec = SSHManagerUtil.setChannelExec(session, manager,script);
            InputStream inputStream = channelExec.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line).append("\n");
                socketMessage.setObj(line);
                webSocketSession.sendMessage(new TextMessage(JSONUtil.toJsonStr(socketMessage)));
            }
            if(StrUtil.isBlank(result.toString())){
                socketMessage.setObj("Please check the server connection status.Status 500");
                webSocketSession.sendMessage(new TextMessage(JSONUtil.toJsonStr(socketMessage)));
            }
            closeEvent(manager);
        }catch (Exception e){
            try {
                socketMessage.setType(topic);
                socketMessage.setObj(e.getMessage());
                webSocketSession.sendMessage(new TextMessage(JSONUtil.toJsonStr(socketMessage)));
                socketMessage.setObj("Please check the server connection status.Status 500");
                webSocketSession.sendMessage(new TextMessage(JSONUtil.toJsonStr(socketMessage)));
            }catch (Exception ex){}
        }finally {
            callBack.accept(result.toString(),webSocketSession);
        }
        return result.toString();
    }

    @Override
    public String execScript(String topic, SettingUserVO user, SSHInfoDTO sshInfoDTO, String command) {
        //得到socket
        StringBuilder result = new StringBuilder();
        SocketMessageVO<String> socketMessage = BeanUtil.copyProperties(socketMessageVO, SocketMessageVO.class);
        WebSocketSession webSocketSession = SocketSessionManager.get(user);
        try {
            TerminalSessionManager.Manager manager = new TerminalSessionManager.Manager();
            Session session = SSHManagerUtil.setSession(manager, sshInfoDTO);
            // 执行脚本
            ChannelExec channelExec = SSHManagerUtil.setChannelExec(session, manager,command);
            InputStream inputStream = channelExec.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line).append("\n");
                socketMessage.setType(topic);
                socketMessage.setObj(line);
                webSocketSession.sendMessage(new TextMessage(JSONUtil.toJsonStr(socketMessage)));
            }
            closeEvent(manager);
        }catch (Exception e){
            try {
                socketMessage.setType(topic);
                socketMessage.setObj(e.getMessage());
                webSocketSession.sendMessage(new TextMessage(JSONUtil.toJsonStr(socketMessage)));
                e.printStackTrace();
            }catch (Exception ex){}
        }
        return result.toString();
    }


}
